﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ILOG.Concert;
using ILOG.CPLEX;

namespace testqwe
{
    //生成排样方案
    class GenSchema
    {
        public int length;
        public int width;
        public double[,] A = null;// m行 n列的二维矩阵，表示第n 种排样方式中包含第m 种毛坯的数量
        public double[] X = null;//n列   排样方式所需切割的板材数
        public int[] B = null;//需求数量
        double[] C = null;
        double[] V = null;
        double[,] AA = null; //A的逆矩阵
        int[] D = null;
        int Num;
        int patternType;
        public int sheetnum;
        Stripe[] pstripe;
        Trapezoid_stripe[] tstripe;
        public List<int[]> presult;//结果的排样结果，包含各毛坯的数量信息
        public List<double> xresult;
        List<Pattern> patternlist;//中间list
        public List<Pattern> result_pattern;//结果的排样方式，包含有具体排样图
        static double RC_EPS = 1.0e-6;//很小的整数，这里用来代表0
        public GenSchema(int l, int w, int[] d, int[] b, double[] v, int type)
        {
            patternType = type;
            length = l;
            width = w;
            D = d;
            B = b;
            V = v;
            Num = Constant.BLK_NUM; ;
            A = new double[Num, Num];
            X = new double[Num];
            init_A();//初始化矩阵A
            init_X();//初始化结果矩阵X
            C = init_C();//初始化价值矩形C（忘记用到没有）
            presult = new List<int[]>();
            xresult = new List<double>();
            patternlist = new List<Pattern>();
            result_pattern = new List<Pattern>();
        }

        //用对偶单纯形法来求解问题得到近似最优解方案
        public void Generate_Schema()
        {
            try
            {
                //新建一个Cplex问题
                Cplex cutSolver = new Cplex();
                //目标函数最小
                IObjective obj = cutSolver.AddMinimize();
                //满足的条件
                IRange[] Fill = new IRange[B.Length];
                //用来存储各种排样方式
                ArrayList cut_list = new ArrayList();

                List<int[]> result = new List<int[]>();

                //初始化F
                for (int f = 0; f < B.Length; f++)
                {
                    //大于等于B
                    Fill[f] = cutSolver.AddRange(B[f], System.Double.MaxValue);
                }
                int m = B.Length;

                //初始化A
                for (int s = 0; s < m; s++)
                {
                    //column.And(cutSolver.Column(Fill[s], 1.0));
                    cut_list.Add(
                        cutSolver.NumVar(
                        cutSolver.Column(obj, 1).And(cutSolver.Column(Fill[s], 1.0))
                        , 0.0, System.Double.MaxValue));
                    int[] Q = new int[m];
                    Q[s] = 1;
                    result.Add(Q);
                    patternlist.Add(new Pattern());
                }

                cutSolver.SetParam(Cplex.IntParam.RootAlg, Cplex.Algorithm.Primal);
                int[] P = new int[Num];
                double c = length * width;
                /// PATTERN-GENERATION PROBLEM 
                /// 生成排样
                /// 
                /// COLUMN-GENERATION PROCEDURE 
                /// 
                init_stripe();//初始化条带信息


                //看成是一个构造A的过程
                for (;;)
                {
                    //求解一次问题
                    cutSolver.Solve();
                    //得到对偶值，即是各毛坯的最新价值
                    V = cutSolver.GetDuals(Fill);
                    //生成当前最优排样方式
                    Plate plate2 = new Plate(length, width, D, V, tstripe, pstripe);
                    plate2.getPattern(patternType);
                    //排样方式结果
                    P = plate2.P;

                    //将具体排样方式添加到结果集
                    if (patternType == 1)
                    {
                        patternlist.Add(new Pattern(plate2.divid_lineoft, plate2.divid_line, plate2.t_pattern, plate2.p_pattern, plate2.t_patternforright, plate2.pattern_type));//不对称排样
                    }
                    else
                    {
                        patternlist.Add(new Pattern(plate2.divid_line, plate2.t_pattern, plate2.p_pattern, plate2.pattern_type));//对称排样
                    }
                    
                    
                    double pvalue = 0.0;
                    for (int j = 0; j < m; j++)
                    {
                        pvalue += P[j] * V[j];
                    }
                    if (1 - pvalue > -RC_EPS) break;
                    result.Add(P);
                    //  A又要添加一列
                    Column column = cutSolver.Column(obj, 1.0);
                    for (int q = 0; q < m; q++)
                        column = column.And(cutSolver.Column(Fill[q], P[q]));
                    cut_list.Add(cutSolver.NumVar(column, 0.0, System.Double.MaxValue));
                }
                //A已经构造完毕
                //为X解添加正整数约束
                for (int q = 0; q < cut_list.Count; q++)
                    cutSolver.Add(cutSolver.Conversion((INumVar)cut_list[q], NumVarType.Int));
                //求解不等式
                cutSolver.Solve();
                System.Console.WriteLine("Solution status = " + cutSolver.GetStatus());
                //整理结果
                for (int i = 0; i < cut_list.Count; i++)
                {
                    //A中某一列对应的X中的值，即该排样方式使用的次数
                    double xed = cutSolver.GetValue((INumVar)cut_list[i]);
                    //如果次数不为0，就将之添加到结果中
                    if (xed != 0)
                    {
                        xresult.Add(xed);
                        presult.Add(result[i]);
                        result_pattern.Add(patternlist[i]);
                    }

                }
                //一个实例完毕
                cutSolver.End();


            }
            catch (ILOG.Concert.Exception exc)
            {
                System.Console.WriteLine("Concert exception '" + exc + "' caught");
            }
        }


        private void init_stripe()
        {
            pstripe = new Stripe[Constant.BLK_NUM];
            tstripe = new Trapezoid_stripe[Constant.BLK_NUM];
            int max = (length > width) ? length : width;

            double hypotenuse = width * Constant.THIRD_OF_SQRT_THREE;
            int lenForY = (int)(width * Constant.THIRD_OF_SQRT_THREE * 2);
            int lenForX = (int)(max - hypotenuse);
            int maxLen = (lenForX > lenForY) ? lenForX : lenForY;
            // double bottom = length - ((length - hypotenuse) / 2);
            double bottom = length;
            for (int i = 0; i < Constant.BLK_NUM; i++)
            {
                pstripe[i] = new Stripe(D[i], maxLen);
            }
            for (int i = 0; i < Constant.BLK_NUM; i++)
            {
                tstripe[i] = new Trapezoid_stripe(bottom, D[i]);
            }
        }

        private void init_A()
        {
            for (int i = 0; i < Num; i++)
            {
                for (int j = 0; j < Num; j++)
                {
                    if (j == i)
                    {
                        A[i, j] = 1;
                        // AA[i, j] = 1;
                    }
                    else
                    {
                        A[i, j] = 0;
                        //AA[i, j] = 0;
                    }
                }
            }
        }
        private double[] init_C()
        {
            double v = length * width;
            double[] c = new double[Num];
            for (int i = 0; i < Num; i++)
                c[i] = v;
            return c;
        }

        private void init_X()
        {
            for (int i = 0; i < Num; i++)
            {
                X[i] = B[i];
            }
        }
    }
}
